﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Reflection;
using System.Web.Security;

using Revis.VClinicNet.App.Internal;
using Revis.VClinicNet.Core.Domain.Credentials;
using Revis.VClinicNet.App.Internal.ServiceImpl;
using Revis.VClinicNet.App.Internal.Dto;
using Revis.VClinicNet.App.Internal.Dto.Mappers;
using Revis.VClinicNet.Core.Domain;
using Revis.VClinicNet.Core.Domain.Repository;
using Revis.VClinicNet.Core.Domain.Persistence.Nh;

using Autofac;
using Autofac.Integration.Web;
using Autofac.Integration.Web.Mvc;
using AutofacContrib.DynamicProxy2;
using NHibernate;
using NHibernate.Cfg;
using NHibernate.Context;
using NHibernate.Tool.hbm2ddl;
using Revis.VClinicNet.UI.Internal.Mvc.Infrastructure;

namespace Revis.VClinicNet.UI.Internal.Mvc
{
    // Note: For instructions on enabling IIS6 or IIS7 classic mode, 
    // visit http://go.microsoft.com/?LinkId=9394801

    public class MvcApplication : System.Web.HttpApplication, IContainerProviderAccessor
    {
        static private IContainerProvider _containerProvider;
        static private IContainer _container;
        static private ISessionFactory _sessionFactory;

        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Login", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
        }

        protected void Application_Start()
        {
            InitializeNHibernate();
            InitializeAutofacContainer(_sessionFactory);
            AreaRegistration.RegisterAllAreas();
            RegisterRoutes(RouteTable.Routes);
        }

        public override void Init()
        {
            base.Init();
            InitializeHandlers();
        }

        #region NHibernate Initialization

        protected void InitializeNHibernate()
        {
            log4net.Config.XmlConfigurator.Configure();
            Configuration configuration = new Configuration();
            configuration.Configure();
            _sessionFactory = configuration.BuildSessionFactory();
            //DatabaseSchemaExport(configuration);
        }

        protected void DatabaseSchemaExport(Configuration configuration)
        {
            new SchemaExport(configuration).Execute(false, true, false);
        }

        #endregion

        #region Autofac Initialization

        protected void InitializeAutofacContainer(ISessionFactory factory)
        {
            ContainerBuilder builder = new ContainerBuilder();

            builder.RegisterControllers(Assembly.GetExecutingAssembly());
            builder.RegisterInstance<ISessionFactory>(factory);
            RegisterServicesInContainer(builder);
            RegisterPasswordEncrypter(builder);
            RegisterRepositoriesInContainer(builder);
            RegisterDtoMappings(builder);

            _container = builder.Build();
            _containerProvider = new ContainerProvider(_container);
            ControllerBuilder.Current.SetControllerFactory(new AutofacControllerFactory(ContainerProvider));

            ResolveDtoMappings(_container);
        }

        private void RegisterPasswordEncrypter(ContainerBuilder builder)
        {
            builder.RegisterType<Sha1PasswordEncrypter>().As<IPasswordEncrypter>();
        }

        protected void RegisterDtoMappings(ContainerBuilder builder)
        {
            builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
                .AssignableTo<IDtoMapper>().As<IDtoMapper>();
            builder.RegisterType<DtoMapperInitializer>().As<IDtoMapperInitializer>();
        }

        protected void ResolveDtoMappings(IContainer container)
        {
            IDtoMapperInitializer dtoInitializer = container.Resolve<IDtoMapperInitializer>();
            dtoInitializer.Initialize();
        }

        private void RegisterServicesInContainer(ContainerBuilder builder)
        {
            builder.RegisterType<DoctorService>().As<IDoctorService>();
            builder.RegisterType<EntryService>().As<IEntryService>();
            builder.RegisterType<VisitService>().As<IVisitService>();
            builder.RegisterType<WorkTimeService>().As<IWorkTimeService>();
            builder.RegisterType<WorkerUserService>().As<IWorkerUserService>();
            builder.RegisterType<PatientService>().As<IPatientService>();
            builder.RegisterType<PatientUserService>().As<IPatientUserService>();
            builder.RegisterType<DataService>().As<IDataService>();
        }

        private void RegisterRepositoriesInContainer(ContainerBuilder builder)
        {
            builder.RegisterType<DoctorRepository>().As<IDoctorRepository>();
            builder.RegisterType<PatientRepository>().As<IPatientRepository>();
            builder.RegisterType<WorkTimeRepository>().As<IWorkTimeRepository>();
            builder.RegisterType<WorkerUserRepository>().As<IWorkerUserRepository>();
            builder.RegisterType<VisitRepository>().As<IVisitRepository>();
            builder.RegisterType<PatientRepository>().As<IPatientRepository>();
            builder.RegisterType<EntryRepository>().As<IEntryRepository>();
            builder.RegisterType<WorkerRepository>().As<IWorkerRepository>();
            builder.RegisterType<PatientUserRepository>().As<IPatientUserRepository>();
        }

        #endregion



        public IContainerProvider ContainerProvider
        {
            get { return _containerProvider; }
        }

        #region Main initialization

        private static void InitializeMembership()
        {
            IWorkerUserService iwus = _container.Resolve<IWorkerUserService>();
            (Membership.Provider as IMembershipInitializer).Initialize(iwus);
            (Roles.Provider as IRoleProviderInitializer).Initialize(iwus);
        }

        private void InitializeHandlers()
        {
            PreRequestHandlerExecute += PreRequestHandler;
            PostRequestHandlerExecute += PostRequestHandler;
        }

        private static void PreRequestHandler(object sender, EventArgs e)
        {
            CurrentSessionContext.Bind(_sessionFactory.OpenSession());
            InitializeMembership();
        }

        private static void PostRequestHandler(object sender, EventArgs e)
        {
            ISession session = CurrentSessionContext.Unbind(_sessionFactory);
            if (session != null) {
                session.Flush();
                session.Dispose();
            }
        }

        #endregion
    }
}